package com.punai.config.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.punai.common.core.page.TableDataInfo;
import com.punai.common.exception.base.BaseException;
import com.punai.common.utils.SecurityUtils;
import com.punai.common.utils.ServletUtils;
import com.punai.config.constants.PnConfigConstants;
import com.punai.config.domain.ConfigInventoryLib;
import com.punai.config.mapper.ConfigInventoryLibMapper;
import com.punai.config.service.ConfigGenerateCodeService;
import com.punai.config.service.IndicatorItemService;
import com.punai.config.sqlitedao.IndicatorItemRepository;
import com.punai.config.sqlitedao.TemplateLinkItemRepository;
import com.punai.config.sqlitedomain.ConfigIndicatorItem;
import com.punai.config.sqlitedomain.TemplateLinkItem;
import com.punai.config.sqlitedomain.vo.ConfigIndicatorItemVo;
import com.punai.standard.domain.StaClFee;
import com.punai.standard.domain.StaGxFee;
import com.punai.standard.domain.StaJxFee;
import com.punai.standard.domain.StaVersion;
import com.punai.standard.domain.constants.StaConstants;
import com.punai.standard.mapper.StaClFeeMapper;
import com.punai.standard.mapper.StaGxFeeMapper;
import com.punai.standard.mapper.StaJxFeeMapper;
import com.punai.standard.mapper.StaVersionMapper;
import com.punai.standard.service.IStaGxChapterService;
import org.apache.commons.collections4.ListValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class IndicatorItemServiceImpl implements IndicatorItemService {

    @Autowired
    private IndicatorItemRepository indicatorItemRepository;
    @Autowired
    private TemplateLinkItemRepository templateLinkItemRepository;
    @Autowired
    private ConfigGenerateCodeService configGenerateCodeService;
    @Autowired
    private ConfigInventoryLibMapper configInventoryLibMapper;
    @Autowired
    private StaVersionMapper staVersionMapper;
    @Autowired
    private StaGxFeeMapper staGxFeeMapper;
    @Autowired
    private StaClFeeMapper staClFeeMapper;
    @Autowired
    private StaJxFeeMapper staJxFeeMapper;
    @Autowired
    private IStaGxChapterService iStaGxChapterService;
    @Override
    public TableDataInfo getMainTableData(ConfigIndicatorItemVo vo) {
        List<ConfigIndicatorItem> all = indicatorItemRepository.findAllByModel(vo);
        for (ConfigIndicatorItem one : all) {
            if(StrUtil.equals("1", one.getClassification()) && StrUtil.isNotEmpty(one.getConditions())){
                //处理人材机关键字回显
                ConfigIndicatorItemVo.Conditions conditions = JSONUtil.toBean(one.getConditions(), ConfigIndicatorItemVo.Conditions.class);
                String name = conditions.getName();
                String unit = conditions.getUnit();
                one.setAttr("名称:"+name+"单位:"+unit);
            }
        }
        int total = indicatorItemRepository.countByModel(vo);
        return new TableDataInfo(all, total);
    }

    @Override
    public ConfigIndicatorItemVo getInfo(ConfigIndicatorItemVo vo) {
        ConfigIndicatorItem one = indicatorItemRepository.findOneById(vo.getId());
        ConfigIndicatorItemVo res = new ConfigIndicatorItemVo();
        BeanUtil.copyProperties(one,res);
        List<String> QdIdStrList = new ArrayList<>();
        List<String> excludeQdIdStrList = new ArrayList<>();
        String qdIdStr = one.getQdIdStr();
        String excludeQdIdStr = one.getExcludeQdIdStr();
        if (qdIdStr != null){
            QdIdStrList = Arrays.asList(one.getQdIdStr().split(",", -1));
        }
        if (excludeQdIdStr!=null){
            excludeQdIdStrList = Arrays.asList(one.getExcludeQdIdStr().split(",", -1));
        }
        if(StrUtil.equals("0", one.getClassification()) && StrUtil.isNotEmpty(res.getConditions())){
            ConfigIndicatorItemVo.Conditions conditions = JSONUtil.toBean(res.getConditions(), ConfigIndicatorItemVo.Conditions.class);
            res.setConditionsObj(conditions);
            if (StrUtil.equals(vo.getMatchType(), "match")) {
                res.setMatchName(conditions.getName());
                res.setMatchUnit(conditions.getUnit());
                res.setDeCode(conditions.getQuota());
                res.setDeName(conditions.getQuotaname());
                res.setDeUnit(conditions.getQuotaunit());
                Map<String, String> listcode = conditions.getListcode();
                for (Map.Entry<String, String> entry : listcode.entrySet()) {
                    List<String> codeList = Arrays.asList(entry.getValue().split(","));
                    List<String> finalQdIdStrList = QdIdStrList;
                    List<String> selCodes = codeList.stream().filter(a -> finalQdIdStrList.stream().anyMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    List<String> codes = codeList.stream().filter(a ->selCodes.stream().noneMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    res.setMatchCode(String.join(",",codes));
                    res.getSelCodes().addAll(selCodes);
                }
                res.getSelCodes().sort(Comparator.comparing(String::valueOf));
            }
            if (StrUtil.equals(vo.getMatchType(), "exclude")) {
                res.setMatchName(conditions.getExcludename());
                res.setMatchUnit(conditions.getExcludeunit());
                Map<String, String> excludelistcode = conditions.getExcludelistcode();
                for (Map.Entry<String, String> entry : excludelistcode.entrySet()) {
                    List<String> codeList = Arrays.asList(entry.getValue().split(","));
                    List<String> finalExcludeQdIdStrList = excludeQdIdStrList;
                    List<String> selCodes = codeList.stream().filter(a -> finalExcludeQdIdStrList.stream().anyMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    List<String> codes = codeList.stream().filter(a ->selCodes.stream().noneMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    res.setMatchCode(String.join(",",codes));
                    res.getSelCodes().addAll(selCodes);
                }
            }
            if (StrUtil.equals("match", vo.getMatchType()) || StrUtil.equals("exclude", vo.getMatchType())) {
                List<String> selCodes = res.getSelCodes();
                res.getSelCodes().forEach(v -> res.getSelTableData().add(configInventoryLibMapper.selectConfigInventoryLibById(v,SecurityUtils.getCompanyId())));
            }
        }
        if(StrUtil.equals("1", one.getClassification()) && StrUtil.isNotEmpty(res.getConditions())){
            ConfigIndicatorItemVo.Conditions conditions = JSONUtil.toBean(res.getConditions(), ConfigIndicatorItemVo.Conditions.class);
            res.setConditionsObj(conditions);
            if (StrUtil.equals(vo.getMatchType(), "match")) {
                res.setMatchName(conditions.getName());
                res.setMatchUnit(conditions.getUnit());
            }
            if (StrUtil.equals(vo.getMatchType(), "exclude")) {
                res.setMatchName(conditions.getExcludename());
                res.setMatchUnit(conditions.getExcludeunit());
            }
        }
        if(StrUtil.equals("3", one.getType()) && StrUtil.isNotEmpty(res.getConditions())){
            ConfigIndicatorItemVo.Conditions conditions = JSONUtil.toBean(res.getConditions(), ConfigIndicatorItemVo.Conditions.class);
            res.setConditionsObj(conditions);
            if (StrUtil.equals(vo.getMatchType(), "match")) {
                res.setMatchName(conditions.getName());
                res.setMatchUnit(conditions.getUnit());
                res.setDeCode(conditions.getQuota());
                res.setDeName(conditions.getQuotaname());
                res.setDeUnit(conditions.getQuotaunit());
                Map<String, String> listcode = conditions.getListcode();
                for (Map.Entry<String, String> entry : listcode.entrySet()) {
                    List<String> codeList = Arrays.asList(entry.getValue().split(","));
                    List<String> finalQdIdStrList1 = QdIdStrList;
                    List<String> selCodes = codeList.stream().filter(a -> finalQdIdStrList1.stream().anyMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    selCodes.forEach(v->{
                        res.getSelCodes().add(entry.getKey()+"=="+v);
                    });
                    List<String> codes = codeList.stream().filter(a ->selCodes.stream().noneMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    res.setMatchCode(String.join(",",codes));
                }
            }
            if (StrUtil.equals(vo.getMatchType(), "exclude")) {
                res.setMatchName(conditions.getExcludename());
                res.setMatchUnit(conditions.getExcludeunit());
                Map<String, String> excludelistcode = conditions.getExcludelistcode();
                for (Map.Entry<String, String> entry : excludelistcode.entrySet()) {
                    List<String> codeList = Arrays.asList(entry.getValue().split(","));
                    List<String> finalExcludeQdIdStrList1 = excludeQdIdStrList;
                    List<String> selCodes = codeList.stream().filter(a -> finalExcludeQdIdStrList1.stream().anyMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    selCodes.forEach(v->{
                        res.getSelCodes().add(entry.getKey()+"=="+v);
                    });
                    List<String> codes = codeList.stream().filter(a ->selCodes.stream().noneMatch(b -> ObjectUtil.equals(a, b))).collect(Collectors.toList());
                    res.setMatchCode(String.join(",",codes));
                }
            }
            if (StrUtil.equals("match", vo.getMatchType()) || StrUtil.equals("exclude", vo.getMatchType())) {
                List<String> specialtyList = iStaGxChapterService.getSpecialtyList(getCompanyId());
                List<StaVersion> CLstaVersions = staVersionMapper.selectListBySpecId(getCompanyId(), StaConstants.CL_TYPE, null);
                List<StaVersion> JXstaVersions = staVersionMapper.selectListBySpecId(getCompanyId(), StaConstants.JX_TYPE, null);
                List<String> removelist = new ArrayList<>();
                for (String selCode : res.getSelCodes()) {
                    boolean isremove = true;
                    String code = selCode.split("==")[1];
                    for (String specialty : specialtyList) {
                        List<StaVersion> GXstaVersions = staVersionMapper.selectListBySpecId(getCompanyId(), StaConstants.GX_TYPE, specialty);
                        if (GXstaVersions.size() > 0) {
                            StaGxFee staGxFee = staGxFeeMapper.selectOne(
                                    Wrappers.<StaGxFee>lambdaQuery()
                                            .eq(StaGxFee::getVersionId, GXstaVersions.get(0).getId())
                                            .eq(StaGxFee::getCode, code)
                            );
                            if (staGxFee != null){
                                res.getSelTableData().add(staGxFee);
                                isremove=false;
                            }
                        }
                    }
                    if (CLstaVersions.size() > 0) {
                        StaClFee staClFee = staClFeeMapper.selectOne(
                                Wrappers.<StaClFee>lambdaQuery()
                                        .eq(StaClFee::getVersionId, CLstaVersions.get(0).getId())
                                        .eq(StaClFee::getCode, code)
                        );
                        if (staClFee != null) {
                            res.getSelTableData().add(staClFee);
                            isremove = false;
                        }
                    }
                    if (JXstaVersions.size() > 0) {
                        StaJxFee staJxFee = staJxFeeMapper.selectOne(
                                Wrappers.<StaJxFee>lambdaQuery()
                                        .eq(StaJxFee::getVersionId, JXstaVersions.get(0).getId())
                                        .eq(StaJxFee::getCode, code)
                        );
                        if (staJxFee != null) {
                            res.getSelTableData().add(staJxFee);
                            isremove = false;
                        }
                    }
                    if(isremove) removelist.add(selCode);
                }
                removelist.forEach(v-> res.getSelCodes().remove(v));
            }
        }
        if(StrUtil.equals("BZ",vo.getMatchType()) && StrUtil.isNotEmpty(res.getFormula())){
            StringBuilder Formula= new StringBuilder();
            String[] split = res.getFormula().split("}");
            for (String s : split) {
                String fh = s.substring(0, s.indexOf("{"));
                String id = s.substring(s.indexOf("{") + 1);
                ConfigIndicatorItem oenOfFormula = indicatorItemRepository.findOneById(id);
                if(oenOfFormula==null)continue;
                res.getSelCodes().add(oenOfFormula.getCode());
                res.getSelTableData().add(oenOfFormula);
                Formula.append(fh).append("{").append(oenOfFormula.getCode()).append("}");
            }
            res.setFormula(Formula.toString());
        }
        return res;
    }

    @Override
    public String getNextCode() {
        return configGenerateCodeService.getNextCode(PnConfigConstants.CODE_TYPE.IND_CODE);
    }

    @Override
    public ConfigIndicatorItemVo save(ConfigIndicatorItemVo vo) {
        try {
            String formula = vo.getFormula();
            if(StrUtil.isNotEmpty(formula)){
                StringBuilder Formula = new StringBuilder();
                String[] split = formula.split("}");
                for (String s : split) {
                    String fh = s.substring(0, s.indexOf("{"));
                    String code = s.substring(s.indexOf("{") + 1);
                    ConfigIndicatorItem oenOfFormula = indicatorItemRepository.findOneByCode(code);
                    Formula.append(fh).append("{").append(oenOfFormula.getId()).append("}");
                }
                vo.setFormula(Formula.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("表达式不合法,请使用{指标项编码}拼接");
        }
        return indicatorItemRepository.save(vo);
    }

    @Override
    public ConfigIndicatorItem remove(ConfigIndicatorItemVo vo) {
        List<TemplateLinkItem> templateLinkItems = templateLinkItemRepository.findByItemId(vo.getId());
        if(templateLinkItems.size()>0) throw new BaseException("模板管理中存在该项关联关系,不能删除");
        return indicatorItemRepository.delete(vo.getId());
    }

    @Override
    public ConfigIndicatorItem settingUnitConver(ConfigIndicatorItemVo vo) {
        return indicatorItemRepository.settingUnitConver(vo);
    }

    @Override
    public ConfigIndicatorItem settingMatchingRules(ConfigIndicatorItemVo vo) {
        ConfigIndicatorItem one = indicatorItemRepository.findOneById(vo.getId());
        String conditionsJson = one.getConditions();
        ConfigIndicatorItemVo.Conditions conditions = new ConfigIndicatorItemVo.Conditions();
        if (StrUtil.isNotEmpty(conditionsJson))
            conditions = JSONUtil.toBean(conditionsJson, ConfigIndicatorItemVo.Conditions.class);
        List<String> selCodes = vo.getSelCodes();
        Set<String> matchSelIds = new HashSet<>();
        Set<String> excludeSelIds = new HashSet<>();
        if(StrUtil.equals("0", one.getClassification())){//清单指标项
            List<ConfigInventoryLib> configInventoryLibs = new ArrayList<>();
            String matchCode = vo.getMatchCode();
            List<String> matchCodeList = new ArrayList<>();
            if (StrUtil.isNotEmpty(matchCode)) {
                //因为清单编码目前可以重复，这块功能以后待做
                matchCodeList = Arrays.asList(matchCode.split(",", -1));
            }
            selCodes.forEach(v -> configInventoryLibs.add(configInventoryLibMapper.selectConfigInventoryLibById(v,SecurityUtils.getCompanyId())));
            ListValuedMap<String, ConfigInventoryLib> listMap = new ArrayListValuedHashMap<>();
            configInventoryLibs.forEach(v->{
                listMap.put(v.getProfessionalEngineering(),v);
            });
            if (StrUtil.equals(vo.getMatchType(), "match")) {
                //匹配  编码匹配并非真实的编码匹配，是将code列为清单的code匹配和selCode同等(排除同理)
                conditions.setName(vo.getMatchName());
                conditions.setUnit(vo.getMatchUnit());
                conditions.setQuota(vo.getDeCode());
                conditions.setQuotaname(vo.getDeName());
                conditions.setQuotaunit(vo.getDeUnit());
                Map<String, String> listcode = conditions.getListcode();
                listcode.clear();
                if (CollUtil.isNotEmpty(selCodes)){
                    for (String key : listMap.keySet()) {
                        List<String> configInventoryIds = listMap.get(key).stream().map(ConfigInventoryLib::getId).collect(Collectors.toList());
                        if (CollUtil.isNotEmpty(matchCodeList)){
                            configInventoryIds.addAll(matchCodeList);
                        }
                        listcode.put(key, String.join(",", configInventoryIds));
                    }
                }else {
                    if (CollUtil.isNotEmpty(matchCodeList)){
                        listcode.put(vo.getInventoryStandard(), String.join(",", String.join(",",matchCodeList)));
                    }
                }
                matchSelIds.addAll(selCodes);
                one.setQdIdStr(String.join(",",matchSelIds));
            }
            if (StrUtil.equals(vo.getMatchType(), "exclude")) {
                //排除
                conditions.setExcludename(vo.getMatchName());
                conditions.setExcludeunit(vo.getMatchUnit());
                Map<String, String> excludelistcode = conditions.getExcludelistcode();
                excludelistcode.clear();
                if (CollUtil.isNotEmpty(selCodes)){
                    for (String key : listMap.keySet()) {
                        List<String> configInventoryIds = listMap.get(key).stream().map(ConfigInventoryLib::getId).collect(Collectors.toList());
                        if (CollUtil.isNotEmpty(matchCodeList)){
                            configInventoryIds.addAll(matchCodeList);
                        }
                        excludelistcode.put(key, String.join(",", String.join(",", configInventoryIds)));
                    }
                }else {
                    if (CollUtil.isNotEmpty(matchCodeList)){
                        excludelistcode.put(vo.getInventoryStandard(), String.join(",", String.join(",",matchCodeList)));
                    }
                }
                excludeSelIds.addAll(selCodes);
                one.setExcludeQdIdStr(String.join(",",excludeSelIds));
            }
        } else if (StrUtil.equals("1", one.getClassification())) {
            if (StrUtil.equals(vo.getMatchType(), "match")) {
                //匹配
                conditions.setName(vo.getMatchName());
                conditions.setUnit(vo.getMatchUnit());
                one.setQdIdStr(String.join(",",matchSelIds));
            }
            if (StrUtil.equals(vo.getMatchType(), "exclude")) {
                //排除
                conditions.setExcludename(vo.getMatchName());
                conditions.setExcludeunit(vo.getMatchUnit());
                one.setExcludeQdIdStr(String.join(",",excludeSelIds));
            }
        } else if(StrUtil.equals("3", one.getType())){//成本费用项指标项
            String matchCode = vo.getMatchCode();
            List<String> matchCodeList = new ArrayList<>();
            if (StrUtil.isNotEmpty(matchCode)) {
                matchCodeList = Arrays.asList(matchCode.split(",", -1));
            }
            ListValuedMap<String, String> valuedHashMap = new ArrayListValuedHashMap<>();
            for (String str : selCodes) {
                String chapterId = str.split("==")[0];
                valuedHashMap.put(chapterId, str.split("==")[1]);
            }
            if (StrUtil.equals(vo.getMatchType(), "match")) {
                //匹配  编码匹配并非真实的编码匹配，是将code列为清单的code匹配和selCode同等(排除同理)
                conditions.setName(vo.getMatchName());
                conditions.setUnit(vo.getMatchUnit());
                Map<String, String> listcode = conditions.getListcode();
                listcode.clear();
                if (CollUtil.isNotEmpty(selCodes)){
                    for (String key : valuedHashMap.keySet()) {
                        List<String> list = valuedHashMap.get(key);
                        matchSelIds.addAll(list);
                        if (CollUtil.isNotEmpty(matchCodeList)){
                            list.addAll(matchCodeList);
                        }
                        listcode.put(key, String.join(",", list));
                    }
                }else {
                    if (CollUtil.isNotEmpty(matchCodeList)){
                        listcode.put("999", String.join(",", String.join(",",matchCodeList)));
                    }
                }
                one.setQdIdStr(String.join(",",matchSelIds));
            }else {
                conditions.setExcludename(vo.getMatchName());
                conditions.setExcludeunit(vo.getMatchUnit());
                Map<String, String> excludelistcode = conditions.getExcludelistcode();
                excludelistcode.clear();
                if (CollUtil.isNotEmpty(selCodes)){
                    for (String key : valuedHashMap.keySet()) {
                        List<String> configInventoryIds = valuedHashMap.get(key);
                        excludeSelIds.addAll(configInventoryIds);
                        if (CollUtil.isNotEmpty(matchCodeList)){
                            configInventoryIds.addAll(matchCodeList);
                        }
                        excludelistcode.put(key, String.join(",", configInventoryIds));
                    }
                }else {
                    if (CollUtil.isNotEmpty(matchCodeList)){
                        excludelistcode.put("999", String.join(",", String.join(",",matchCodeList)));
                    }
                }
                one.setExcludeQdIdStr(String.join(",",excludeSelIds));
            }
        }
        one.setConditions(JSONUtil.toJsonStr(conditions));
        one=indicatorItemRepository.settingMatchingRules(one);
        return one;
    }

    protected Long getCompanyId() {
        return ServletUtils.getParameterToLong("paramCompId", SecurityUtils.getCompanyId());
    }
}
